/**
**************************************************************************************
*Founder Effect                                                                      *
*Copyright (C) 2006-2007, 5d Studios (www.5d-Studios.com)                            *
*                                                                                    *
*This library is free software; you can redistribute it and/or                       *
*modify it under the terms of the GNU Lesser General Public                          *
*License as published by the Free Software Foundation; either                        *
*version 2.1 of the License, or (at your option) any later version.                  *
*                                                                                    *
*This library is distributed in the hope that it will be useful,                     *
*but WITHOUT ANY WARRANTY; without even the implied warranty of                      *
*MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU                   *
*Lesser General Public License for more details.                                     *
*                                                                                    *
*You should have received a copy of the GNU Lesser General Public                    *
*License along with this library; if not, write to the Free Software                 *
*Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA      *
**************************************************************************************
*/
#pragma once
#include <map>

#include "InputBuffer.h"
#include "Binder.h"

#include "../Commands.h"
#include "../IProcess.h"

/**
=============================
Input subsystem interface
=============================
*/
class IInput : public IProcess
{
public:
    /** Initialize the input system */
    virtual int Init()=0;
    /** Poll for events */
	virtual void Update(float dt)=0;
    /** Shutdown */
	virtual void Shutdown()=0;

    /*----------------------------
        Handle Joystick Input
    -----------------------------*/

    /** Test to see if there is a joystick availible, return the count */
    virtual int CheckJoystick()=0;
    /** Enable the joystick module */
    virtual void EnableJoystick()=0;
    /** Test to see if the joystick module is up */
    bool JoystickEnabled() { return m_joystickEnabled; };
    /** Check the x-axis */
    virtual int GetJoystickX()=0;
    /** Check the y-axis */
    virtual int GetJoystickY()=0;
    /** Test to see if a button is down */
    virtual int IsJoystickButtonDown(int button, bool stamp=false)=0;

    /*----------------------------
        Handle the mouse 
    -----------------------------*/

    /** Get the mouse x-pos */
    virtual int GetMouseX()=0;
    /** Get the mouse y-pos */
	virtual int GetMouseY()=0;

    /** Get the change in x */
    virtual int GetDeltaMX()=0;
    /** Get the change in y */
    virtual int GetDeltaMY()=0;
    /** Test to see if a mouse button is down */
    virtual bool IsButtonDown( int button, bool stamp=false )=0;
    /** Test to see if a button is released */
    virtual bool ButtonReleased( int button )=0;

    /*---------------------------------
        Handle keyboard 
    ----------------------------------*/

    /** Test to see if a key is down */
    virtual bool IsKeyDown( int key, bool stamp=false )=0;
    /** Test to see if a key is released */
    virtual bool KeyReleased( int key )=0;
    

    /** Fetch and input buffer */
    InputBuffer* GetInputBuffer(int buffer) {
        return buffList[buffer];
    };

    /** Get the Binder - a binder maps keys to functions */
    Binder* GetBinder() { return &m_binder; }; 
    /**
    =============================
    Activate a desired buffer
    =============================
    */
    void ActivateBuffer(int i) { 
        if ( buffList.empty() )
            return;
        
        if ( i > buffList.size() )
            i = 0;

        m_current = i;
        // deactivate old buffer
        if ( m_currentBuffer )
            m_currentBuffer->SetActive( false );

        m_currentBuffer = buffList[m_current];
        // activate new buffer
        if ( m_currentBuffer )
            m_currentBuffer->SetActive( true );
        
    };

    /** Deactivate a buffer */
    void DeactivateBuffer( int buf ) {
        if ( buffList.empty() )
            return;
        if ( buf > buffList.size() )
            buf = 0;
        buffList[buf]->SetActive( false );
    };

    /** Add a buffer */
    void AddBuffer( InputBuffer* b, int buf ) {
        if ( buffList.find( buf ) == buffList.end() )
        {    buffList[buf] = b;
        } else {
             if ( buffList[buf] )
             { delete buffList[buf]; }
             buffList[buf] = b;
        }
    };

    /** Remove a buffer */
    void RemoveBuffer( int buf ) {
        std::map<int, InputBuffer* >::iterator it = buffList.find( buf );
        if ( it != buffList.end() )
        {   buffList.erase( it );
            if ( it->second ) 
                delete it->second;
        }
        
    }

private:
    Binder m_binder;
protected:
    // current buffer number
    int     m_current;
    // ref to current buffer
    InputBuffer* m_currentBuffer;
    // buff list
    std::map<int, InputBuffer* > buffList;

    // if joystick is availible
    bool m_joystickEnabled;
};

/**
=============================
Bind a command with a key
=============================
*/
class Bind_f : public ICommand
{
public:
    Bind_f() {};
    void Exec(std::string &s);
    ~Bind_f() {};
};

/**
=============================
UnBind a command with a key
=============================
*/
class UnBind_f : public ICommand
{
public:
    UnBind_f() {};
    void Exec(std::string &s);
    ~UnBind_f() {};
};

/**
=============================
UnBindAll a command with a key
=============================
*/
class UnBindAll_f : public ICommand
{
public:
    UnBindAll_f() {};
    void Exec(std::string &s);
    ~UnBindAll_f() {};
};
